﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ArduinoInterOp
{
    internal class ArduinoPinsManager
    {
        private readonly Arduino _arduino;
        private readonly ArduinoSetup _setup;
        private readonly ArduinoPinValuesData _outputPins;
        private readonly ArduinoPinValuesData _inputPins;
        private Arduino arduino;

        internal ArduinoPinsManager(Arduino arduino, ArduinoSetup setup)
        {
            _arduino = arduino;
            _setup = setup;
            _outputPins = new ArduinoPinValuesData(this);
            _inputPins = new ArduinoPinValuesData(this);
            Init();
        }

        public ArduinoPinValuesData OutputPins
        {
            get { return _outputPins; }
        }

        public ArduinoPinValuesData InputPins
        {
            get { return _inputPins; }
        }

        private void Init()
        {
            foreach (var setupData in _setup)
            {
                switch (setupData.Value)
                {
                    case SensorType.Input:
                        InputPins.Add(setupData.Key);
                        break;
                    case SensorType.Output:
                        OutputPins.Add(setupData.Key);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
        }

        internal void UpdateInputPin(byte pinNumber, ushort value, long updateTicks)
        {
            InputPins.UpdatePin(pinNumber, value, updateTicks);
        }

        internal void UpdateOutputPin(byte pinNumber, ushort value, long updateTicks)
        {
            OutputPins.UpdatePin(pinNumber, value, updateTicks);
        }

        internal ArduinoPinValueData GetPinData(byte pinNumber)
        {
            var data = this._inputPins[pinNumber];

            if(data != null)
            {
                return data;
            }

            return this._outputPins[pinNumber];
        }

        internal void NotifyPinHasHandlers(byte pinNumber)
        {
            switch (this._setup[pinNumber])
            {
                case SensorType.Input:
                    _arduino.AddListenerToPin(pinNumber);
                    break;
                case SensorType.Output:
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        internal void NotifyPinHasNoHandlers(byte pinNumber)
        {
            switch (this._setup[pinNumber])
            {
                case SensorType.Input:
                    _arduino.RemoveListenerToPin(pinNumber);
                    break;
                case SensorType.Output:
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }
}
